/**
 * 
 */
package br.com.android.games.daedal.flat;

import java.util.ArrayList;
import java.util.List;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Align;
import android.graphics.Paint.Style;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.MotionEvent;
import android.view.View;
import br.com.android.games.daedal.R;
import br.com.games.daedal.Box;
import br.com.games.daedal.DaedalTeam;
import br.com.games.daedal.Vertex;
import br.com.games.daedal.imp.DaedalBoard;
import br.com.games.daedal.imp.DaedalBox;

/**
 * @author schindler
 * 
 */
public class FlatBoard extends View {

	/**
	 * Holds the square side in dp
	 */
	private RectF mSrcRect = new RectF();

	/**
	 * Margin length
	 */
	private static final int MARGIN = 15;

	/**
	 * Border attribute
	 */
	private float STROKE;

	/**
	 * Back groud color
	 */
	private Paint mWinPaint;

	/**
	 * Back groud color
	 */
	private Paint mStickPaint;

	/**
	 * Back groud color
	 */
	private Paint mSelectedPaint;

	/**
	 * main board
	 */
	private DaedalBoard board;

	/**
	 * Controlador de seleção para cada aresta
	 */
	private List<Edge> edges;

	private int uiSelected = -1, lines = 3, columns = 6;

	private boolean selectEnable = false;

	private int scale, offset, xd, yd;

	private Drawable bg_white;

	private Drawable bg_black;

	private Drawable dots[];

	private Drawable selc[];

	/*
	 * Default contructor
	 */
	public FlatBoard(Context context, AttributeSet attrs) {
		super(context, attrs);

		boolean isClassicMode;

		TypedArray a = context.getTheme().obtainStyledAttributes(attrs,
				R.styleable.FlatBoard, 0, 0);

		try {
			lines = a.getInteger(R.styleable.FlatBoard_lines, lines);
			columns = a.getInteger(R.styleable.FlatBoard_columns, columns);
			isClassicMode = a.getBoolean(R.styleable.FlatBoard_classic, true);
		} finally {
			a.recycle();
		}

		STROKE = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 1,
				getResources().getDisplayMetrics());

		mWinPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
		mWinPaint.setColor(Color.BLACK);
		mWinPaint.setStyle(Style.FILL_AND_STROKE);
		mWinPaint.setTextAlign(Align.CENTER);

		mStickPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
		mStickPaint.setColor(Color.LTGRAY);

		mSelectedPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
		mSelectedPaint.setStrokeWidth(STROKE * 5);
		mSelectedPaint.setStyle(Style.FILL);

		if (!isInEditMode()) {
			this.board = new DaedalBoard(this.lines, this.columns,
					isClassicMode);
			this.dots = new Drawable[] {
					getResources().getDrawable(R.drawable.dot_sample_1),
					getResources().getDrawable(R.drawable.dot_sample_3),
					getResources().getDrawable(R.drawable.dot_sample_2),
					getResources().getDrawable(R.drawable.dot_sample_4), };

			this.selc = new Drawable[] {
					getResources().getDrawable(R.drawable.action_select_dot),
					getResources().getDrawable(R.drawable.action_swipe_down),
					getResources().getDrawable(R.drawable.action_swipe_up),
					getResources().getDrawable(R.drawable.action_swipe_left),
					getResources().getDrawable(R.drawable.action_swipe_right), };

			this.bg_white = getResources().getDrawable(
					R.drawable.player_1_filled);

			this.bg_black = getResources().getDrawable(
					R.drawable.player_2_filled);

			Typeface tf = Typeface.createFromAsset(getResources().getAssets(),
					"jrha.ttf");

			mWinPaint.setTypeface(tf);
		}
		requestFocus();
	}

	/**
	 * Ajustar para o modo classico ou avançado
	 * 
	 * @param isClassic
	 */
	public void setIsClassicMode(boolean isClassic) {
		for (Box b : this.board.getSquares()) {
			((DaedalBox) b).setValue((int) (isClassic ? 1 : 2));
		}
		board.reset();
		invalidate();
	}

	/*
	 * Default contructor
	 */
	public FlatBoard(Context context) {
		this(context, null);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see android.view.View#onMeasure(int, int)
	 */
	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		int parentWidth = MeasureSpec.getSize(widthMeasureSpec);
		int s = (int) (parentWidth - (parentWidth / MARGIN) * 2) / columns;
		setMeasuredDimension(parentWidth, (s * lines)
				+ (int) (parentWidth / MARGIN) * 2);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see android.view.View#onSizeChanged(int, int, int, int)
	 */
	@Override
	protected void onSizeChanged(int w, int h, int oldw, int oldh) {
		super.onSizeChanged(w, h, oldw, oldh);
		int size = (int) (w - (w / MARGIN) * 2);

		scale = (int) ((size / (this.columns)));
		scale = (int) (scale);
		offset = (int) (w / MARGIN);

		mSrcRect.set(offset, offset, scale * columns + offset, scale * lines
				+ offset);

		if (!isInEditMode()) {
			edges = new ArrayList<Edge>();

			for (Vertex v : this.board.getVertexes())
				edges.add(new Edge(v.getLocation(), (int) offset, scale,
						STROKE * 2, selc));

			mWinPaint.setTextSize((scale * 7) / 10);
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see android.view.View#onTouchEvent(android.view.MotionEvent)
	 */
	@Override
	public boolean onTouchEvent(MotionEvent event) {

		int selectedY = (int) event.getY();
		int selectedX = (int) event.getX();
		
		if (event.getAction() == MotionEvent.ACTION_DOWN && isWaiting()) {
			xd = selectedX;
			yd = selectedY;
			for (int i = 0; i < this.edges.size(); i++) {
				Edge e = this.edges.get(i);
				if (!board.getVertexes().get(i).valueBeforeAnalise()) {
					e.setSelected(0, Color.GREEN);
					int s = e.isOver(xd, yd, scale / 3);
					if (s > 0) {
						e.setSelected(1 + s, Color.GREEN);
					}
				}
			}
			postInvalidate();
		} else if (event.getAction() == MotionEvent.ACTION_MOVE && isWaiting()) {
			int s = -1;
			for (int i = 0; i < this.edges.size(); i++) {
				Edge e = this.edges.get(i);
				if (!board.getVertexes().get(i).valueBeforeAnalise())
					if (e.isLyingOn(selectedX, selectedY)) {
						s = i;
						break;
					}
			}

			if (s >= 0) {
				for (int i = 0; i < this.edges.size(); i++) {
					Edge e = this.edges.get(i);
					if (i != s)
						e.setSelected(0, Color.GREEN);
				}
			} else {
				for (int i = 0; i < this.edges.size(); i++) {
					Edge e = this.edges.get(i);
					if (!board.getVertexes().get(i).valueBeforeAnalise()) {
						e.setSelected(0, Color.GREEN);
						s = e.isOver(xd, yd, scale / 3);
						if (s > 0) {
							e.setSelected(1 + s, Color.GREEN);
						}
					}
				}
			}

			postInvalidate();

		} else if ((event.getAction()) == MotionEvent.ACTION_UP && isWaiting()) {
			int toSelect = -1;
			for (int i = 0; i < this.edges.size(); i++) {
				Edge e = this.edges.get(i);
				if (toSelect < 0) {
					if (!board.getVertexes().get(i).valueBeforeAnalise()) {
						if (e.isLyingOn(selectedX, selectedY)) {
							toSelect = i;
							break;
						}
					}
				}
			}
			if (toSelect >= 0) {
				for (int i = 0; i < this.edges.size(); i++) {
					Edge e = this.edges.get(i);
					e.setSelected(0, Color.GREEN);
				}
			}
			uiSelected = toSelect;
		}

		return true;
	}

	/**
	 * Recuperar o tabuleiro para o jogo
	 * 
	 * @return
	 */
	public DaedalBoard getBoard() {
		return this.board;
	}

	/**
	 * 
	 * @param b
	 * @return
	 */
	private boolean isClosed(Box b) {
		boolean result = true;

		for (Vertex v : b.getVertexes()) {
			if (!v.valueBeforeAnalise()) {
				result = false;
				break;
			}
		}

		return result;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see android.view.View#onDraw(android.graphics.Canvas)
	 */
	@Override
	protected void onDraw(Canvas canvas) {
		super.onDraw(canvas);

		if (!isInEditMode()) {
			int idot = 0;

			Drawable d = dots[idot++ % dots.length];
			int[] l = null;

			for (Vertex v : this.board.getVertexes()) {
				l = v.getLocation();
				canvas.drawLine(l[0] * scale + offset, l[1] * scale + offset,
						l[2] * scale + offset, l[3] * scale + offset,
						mStickPaint);
			}

			for (Vertex v : this.board.getVertexes()) {
				l = v.getLocation();
				if (v.valueBeforeAnalise()) {

					if (v.getTeam().equals(DaedalTeam.WHITE)) {
						mSelectedPaint.setARGB(0x7f, 0x61, 0xA7, 0xA7);
					} else if (v.getTeam().equals(DaedalTeam.BLACK)) {
						mSelectedPaint.setARGB(0x7f, 0xEB, 0x03, 0x35);
					}

					canvas.drawLine(l[0] * scale + offset, l[1] * scale
							+ offset, l[2] * scale + offset, l[3] * scale
							+ offset, mSelectedPaint);
				}
			}

			int il = Math.min(d.getMinimumHeight(), scale / 14);

			for (Vertex v : this.board.getVertexes()) {
				l = v.getLocation();

				d.setBounds(l[0] * scale + offset - (il), l[1] * scale + offset
						- (il), l[0] * scale + offset + (il), l[1] * scale
						+ offset + (il));
				d.draw(canvas);
				d = dots[idot++ % dots.length];
			}

			d = dots[idot++ % dots.length];
			d.setBounds(l[2] * scale + offset - (il), l[3] * scale + offset
					- (il), l[2] * scale + offset + (il), l[3] * scale + offset
					+ (il));
			d.draw(canvas);

			Rect recti = new Rect();

			for (Box b : this.board.getSquares()) {
				float x = 0, y = 0;
				Paint font = mWinPaint;

				for (Vertex v : b.getVertexes()) {
					x += (v.getLocation()[0] * scale + offset);
					y += (v.getLocation()[1] * scale + offset);
					x += (v.getLocation()[2] * scale + offset);
					y += (v.getLocation()[3] * scale + offset);
				}

				if (isClosed(b)) {
					Drawable fill;
					if (b.getOwner().equals(DaedalTeam.BLACK)) {
						fill = bg_black;
					} else {
						fill = bg_white;
					}

					recti.left = (int) (x / 8 - (scale / 2 - (STROKE * 2)));
					recti.top = (int) (y / 8 - (scale / 2 - (STROKE * 2)));
					recti.right = recti.left + (int) ((scale - (STROKE * 4)));
					recti.bottom = recti.top + (int) ((scale - (STROKE * 4)));

					fill.setBounds(recti);
					fill.draw(canvas);
				}

				if (b.getValue() > 1) {
					String sv = String.format("%02d", b.getValue());
					font.getTextBounds(sv, 0, 2, recti);
					canvas.drawText(sv, x / 8, y / 8 + (recti.height() / 2),
							font);
				}
			}

			for (Edge e : this.edges) {
				e.paint(canvas);
			}
		} else {
			canvas.drawRect(0, 0, getWidth(), getHeight(), mStickPaint);
			canvas.drawRect(mSrcRect, mWinPaint);
			canvas.drawText("Lines * Columns: " + (lines * columns), MARGIN
					* STROKE, offset + 50, mStickPaint);
		}
	}

	/**
	 * 
	 * @param b
	 */
	public synchronized void waitMove(boolean b) {
		this.selectEnable = b;
	}

	/**
	 * 
	 * @return
	 */
	public synchronized boolean isWaiting() {
		return this.selectEnable;
	}

	/**
	 * 
	 * @return
	 */
	public Vertex getSelected() {
		int pnow = uiSelected = -1;

		try {
			Thread.sleep(100);
			pnow = uiSelected;
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		return pnow >= 0 ? this.board.getVertexes().get(pnow) : null;
	}

	/**
	 * 
	 * @param v
	 * @param color
	 */
	public void select(Vertex v, int color) {
		for (int i = 0; i < this.edges.size(); i++) {
			Edge e = this.edges.get(i);
			e.setSelected(0, 0);
		}
		List<Vertex> vertex = this.board.getVertexes();
		for (int i = 0; i < vertex.size(); i++) {
			if (vertex.get(i).equals(v)) {
				if (color != Color.YELLOW)
					edges.get(i).setSelected(1, color);
				else
					edges.get(i).setSelected(2, color);
				break;
			}
		}
	}
}
